﻿using System;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Phone.Controls;

namespace CacheProviderDemo
{
    using System.Reflection;
    using WP7Contrib.Caching;
    using WP7Contrib.Common;
    using WP7Contrib.Logging;
    using WP7Contrib.Serialization.Helpers;

    public partial class MainPage : PhoneApplicationPage
    {
        private const string ApplicationName = "CacheProviderDemo";
        private ICacheProvider cacheProvider;
        private TimeSpan cacheTimeout;
        private ILog log;

        public MainPage()
        {
            InitializeComponent();

            var extraSerialisationAssemblies = new List<Assembly>(){ this.GetType().Assembly, typeof(SerializeUri).Assembly };

            log = new DebugLog();
            cacheProvider = new IsolatedStorageCacheProvider(ApplicationName, extraSerialisationAssemblies);
            cacheTimeout = TimeSpan.FromSeconds(20);
        }

        private void addValueType_Click(object sender, RoutedEventArgs e)
        {
            var key = Guid.NewGuid().ToString();
            var value =  new CacheValue<int>(42);

            cacheProvider.Add(key, value, cacheTimeout);

            log.Write("Added value type to the cache...");

            var cacheValue = cacheProvider.Get<string, CacheValue<int>>(key);
            var actualValue = cacheValue.Value;

            log.Write("Value type read back from cache, value - '{0}'", actualValue);
        }

        private void addReferenceType_Click(object sender, RoutedEventArgs e)
        {
            var key = new ExampleReferenceTypeKey
                          {
                              FirstName = "Dirk",
                              LastName = "Gently",
                              Url = new Uri("http://wp7contrib.codeplex.com/"),
                              Random = Guid.NewGuid()
                          };

            var value = new List<Guid>();
            for (var i = 0; i < 100; i++)
                value.Add(Guid.NewGuid());

            var alreadyInCache = cacheProvider.Get<ExampleReferenceTypeKey, List<Guid>>(key) != null;
            if (alreadyInCache)
            {
                log.Write("Key already in cache!");
            }

            cacheProvider.Add(key, value, cacheTimeout);

            log.Write("Added reference type to the cache...");

            var cacheValue = cacheProvider.Get<ExampleReferenceTypeKey, List<Guid>>(key);

            log.Write("Reference type read back from cache, list count = {0}", cacheValue.Count);
        }
    }

    public class ExampleReferenceTypeKey : BaseModel, IEquatable<ExampleReferenceTypeKey>
    {
        private string firstName;
        private string lastName;
        private Uri url;
        private Guid random;

        public ExampleReferenceTypeKey()
        {
        }
        
        public string FirstName
        {
            get { return this.firstName; }
            set { this.SetPropertyAndNotify(ref this.firstName, value, () => this.FirstName); }
        }

        public string LastName
        {
            get { return this.lastName; }
            set { this.SetPropertyAndNotify(ref this.lastName, value, () => this.LastName); }
        }

        public Uri Url
        {
            get { return this.url; }
            set { this.SetPropertyAndNotify(ref this.url, value, () => this.Url); }
        }

        public Guid Random
        {
            get { return this.random; }
            set { this.SetPropertyAndNotify(ref this.random, value, () => this.Random); }
        }
        
        public override int GetHashCode()
        {
            return this.CombineHashCodes(FirstName, LastName, Url, Random);
        }

        public static bool operator ==(ExampleReferenceTypeKey k1, ExampleReferenceTypeKey k2)
        {
            return Equals(k1, k2);
        }

        public static bool operator !=(ExampleReferenceTypeKey k1, ExampleReferenceTypeKey k2)
        {
            return !Equals(k1, k2);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return false;
            }

            return obj is ExampleReferenceTypeKey && this.Equals((ExampleReferenceTypeKey)obj);
        }

        public bool Equals(ExampleReferenceTypeKey key)
        {
            if (ReferenceEquals(null, key))
            {
                return false;
            }

            if (this.FirstName != key.FirstName)
            {
                return false;
            }

            if (this.LastName != key.LastName)
            {
                return false;
            }

            if (this.Url != key.Url)
            {
                return false;
            }

            if (this.Random != key.Random)
            {
                return false;
            }

            return true;
        }
    }
}